﻿

#ifndef __STRING_CONVERT_H_
#define __STRING_CONVERT_H_
////////////////////////////////////////////////////////////////////////////////
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
////////////////////////////////////////////////////////////////////////////////
#include <string>
#include <random>
#pragma warning(disable: 4333)
////////////////////////////////////////////////////////////////////////////////
#include <asio++/md5.h>
#include <asio++/configure.h>
////////////////////////////////////////////////////////////////////////////////
template<typename _Ty>
inline void shellsort(_Ty *p, int n){
    _Ty v;
    for (int j, k = (n >> 1); k > 0; k >>= 1){
        for (int i = k; i < n; i++){
            v = p[i];
            for (j = i - k; j >= 0 && v < p[j]; j -= k){
                p[j + k] = p[j];
            }
            p[j + k] = v;
        }
    }
}
////////////////////////////////////////////////////////////////////////////////
inline std::mt19937& G19937(){
    static std::random_device rd;
    static std::mt19937 gen(rd());
    return gen;
}
////////////////////////////////////////////////////////////////////////////////
inline int rand_int(std::mt19937 &gen = G19937()){
    return (int)gen();
}
////////////////////////////////////////////////////////////////////////////////
inline int rand_int(int v1, int v2, std::mt19937 &gen = G19937()){
    std::uniform_int_distribution<> dis(v1, v2);
    return (int)dis(gen);
}
////////////////////////////////////////////////////////////////////////////////
inline int hit(double rate, std::mt19937 &gen = G19937()){
    int rnd_v = 0;
    const int int_v = 100000000;
    const int max_v = (int)(int_v * rate);
    if (rate < 1.0){
        rnd_v = rand_int(0, int_v, gen);
    }
    return (rnd_v < max_v) ? 1 : 0; //命中概率
}
////////////////////////////////////////////////////////////////////////////////
inline int get_rnd_money(int &money, int &count, std::mt19937 &gen = G19937()){
    if (money < 1 || count < 1){
        money = count = 0;
        return 0;
    }
    int average = money / count;
    if (count > 1){
        int min_v = average ? 1 : 0;
        int max_v = std::max(1, average * 2 - 1);
        int delta = min_v ? 1 : count / money;
        average = rand_int(min_v, max_v * delta, gen) / delta;
    }
    money -= average;
    return (--count, average);
}
////////////////////////////////////////////////////////////////////////////////
inline unsigned int v4toi(const char *p, char x = '.') {
    unsigned int m = 0, v = 0;
    do {
        int c = *p;
        if (c == 0 || c == x) {
            if ((v = (v << 8) + m) < 0) {
                return 0;
            }
            else if (!(m = 0)) {
                continue;
            }
        }
        int n = -1;
        switch (*p) {
        case '0': n = 0;
            break;
        case '1': n = 1;
            break;
        case '2': n = 2;
            break;
        case '3': n = 3;
            break;
        case '4': n = 4;
            break;
        case '5': n = 5;
            break;
        case '6': n = 6;
            break;
        case '7': n = 7;
            break;
        case '8': n = 8;
            break;
        case '9': n = 9;
            break;
        default: return 0;
        }
        if ((m = m * 10 + n) > 0xff) {
            return 0;
        }
    } while (*(p++));
    return v;
}
////////////////////////////////////////////////////////////////////////////////
inline const char* itov4(unsigned int v, char x = '.') {
    static char rp[16];
    unsigned char *p = (unsigned char*)&v;
    sprintf(rp, "%d%c%d%c%d%c%d", p[3], x, p[2], x, p[1], x, p[0]);
    return rp;
}
////////////////////////////////////////////////////////////////////////////////
inline int v4mask(int n) {
    return std::max<int>(0, std::min<int>(32, n));
}
////////////////////////////////////////////////////////////////////////////////
inline unsigned int v4begin(unsigned int v, int mask) {
    unsigned int x = ~0;
    mask = v4mask(mask);
    x = (x >> (32 - mask) << (32 - mask));
    return (v & x);
}
////////////////////////////////////////////////////////////////////////////////
inline unsigned int v4count(int mask) {
    mask = v4mask(mask);
    return mask ? (1 << (32 - mask)) : ~0;
}
////////////////////////////////////////////////////////////////////////////////
inline int v4comp(unsigned int v, unsigned int begin, int mask) {
    unsigned int n1 = v4begin(v, mask);
    unsigned int n2 = v4begin(begin, mask);
    unsigned int n3 = (v - begin) & 0x7fffffff;
    return (n1 == n2) ? n3 : -1;
}
////////////////////////////////////////////////////////////////////////////////
inline unsigned short hash16(const void *data, size_t size){
    unsigned short cksum = 0;
    unsigned short *buff = (unsigned short*)data;
    while (size > 1) {
        cksum += *buff++;
        size -= sizeof(unsigned short);
    }
    if (size == 1)
        cksum += *((unsigned char*)buff);

    cksum = (cksum >> 16) + (cksum & 0xffff);
    cksum += (cksum >> 16);
    return (unsigned short)(~cksum);
}
////////////////////////////////////////////////////////////////////////////////
inline unsigned int hash32(const void *key, size_t len){
    const unsigned int m = 0x5bd1e995;
    const int r = 24;
    const int seed = 97;
    unsigned int h = seed ^ (int)len;

    const unsigned char *data = (const unsigned char *)key;
    while (len >= 4) {
        unsigned int k = *(unsigned int *)data;
        k *= m;
        k ^= k >> r;
        k *= m;
        h *= m;
        h ^= k;
        data += 4;
        len -= 4;
    }
    switch (len) {
    case 3: h ^= data[2] << 16;
    case 2: h ^= data[1] << 8;
    case 1: h ^= data[0];
        h *= m;
    };
    h ^= h >> 13;
    h *= m;
    h ^= h >> 15;
    return h;
}
////////////////////////////////////////////////////////////////////////////////
inline unsigned long long hash64(const void *key, size_t len){
    const int r = 24;
    const unsigned int m = 0x5bd1e995;
    const unsigned int seed = 0xee6b27eb;

    unsigned int h1 = seed ^ (int)len;
    unsigned int h2 = 0;

    const unsigned int *data = (const unsigned int*)key;
    while (len >= 8) {
        unsigned int k1 = *data++;
        k1 *= m; k1 ^= k1 >> r; k1 *= m;
        h1 *= m; h1 ^= k1;
        len -= 4;

        unsigned int k2 = *data++;
        k2 *= m; k2 ^= k2 >> r; k2 *= m;
        h2 *= m; h2 ^= k2;
        len -= 4;
    }
    if (len >= 4) {
        unsigned int k1 = *data++;
        k1 *= m; k1 ^= k1 >> r; k1 *= m;
        h1 *= m; h1 ^= k1;
        len -= 4;
    }
    switch (len) {
    case 3: h2 ^= ((unsigned char*)data)[2] << 16;
    case 2: h2 ^= ((unsigned char*)data)[1] << 8;
    case 1: h2 ^= ((unsigned char*)data)[0];
        h2 *= m;
    };

    h1 ^= h2 >> 18; h1 *= m;
    h2 ^= h1 >> 22; h2 *= m;
    h1 ^= h2 >> 17; h1 *= m;
    h2 ^= h1 >> 19; h2 *= m;

    unsigned long long h = h1;
    return ((h << 32) | h2);
}
////////////////////////////////////////////////////////////////////////////////
inline bool uuid_verify(const std::string &uuid){
    if (uuid.size() != 32) {
        return false;
    }
    const char *p = uuid.c_str();
    unsigned short cksum1 = hash16(p, 30) % 100;
    unsigned short cksum2 = (unsigned short)atoi(p + 30);
    return (cksum1 == cksum2);
}
////////////////////////////////////////////////////////////////////////////////
inline std::string uuid_generate(const std::string &key){
    unsigned int now = (unsigned int)time(0);
    unsigned int hash = hash32(key.c_str(), key.size());

    char data[64];
    sprintf(data, "%010u%010u%010u", now, hash, rand_int());
    size_t offset = strlen(data);

    sprintf(data + offset, "%02u", hash16(data, offset) % 100);
    return std::move(std::string(data));
}
////////////////////////////////////////////////////////////////////////////////
inline std::string uuid_generate(){
    char data[32];
    sprintf(data, "%010u", time_get_time());
    return uuid_generate(std::string(data));
}
////////////////////////////////////////////////////////////////////////////////
inline std::string gmt_time_now(time_t now){
    tm *ptm = gmtime(&now);
    char gmtstr[128];
    strftime(gmtstr, 128, "%a, %d %b %Y %X GMT", ptm);
    return std::move(std::string(gmtstr));
}
////////////////////////////////////////////////////////////////////////////////
inline std::string bin2hex(const char *data, size_t size){
    std::string out;
    unsigned char *p = (unsigned char*)data;

    // Show 16 bytes each line.
    size_t lines = size / 16;
    size_t char_last_line = 0;
    if(0 != size % 16){
        char_last_line = size - lines * 16;
    }
    char buf[16];
    unsigned int i = 0;
    for (i = 0; i < lines; ++i){
        out += (sprintf(buf, "%08X ", i * 16), buf);
        int j = 0;
        for (j = 0; j < 16; ++j){
            out += (sprintf(buf, "%02X ", p[16 * i + j]), buf);
            if(j == 7)
                out += "- ";
        }
        out += "    ";
        for (j = 0; j < 16; ++j){
            if (isprint(p[16 * i + j]) && p[16 * i + j] != '%')
                out += (char)p[16 * i + j];
            else
                out += ".";
        }
        out += "\n";
    }
    if (0 != char_last_line){
        out += (sprintf(buf, "%08X ", i * 16), buf);
        size_t j = 0;
        for (j = 0; j < char_last_line; ++j)
        {
            out += (sprintf(buf, "%02X ", p[16 * i + j]), buf);
            if (j == 7 && char_last_line > 8)
                out += "- ";
        }
        size_t k = 0;
        k += ((16 - char_last_line) * 3);
        if (char_last_line <= 8)
            k += 2;
        for (size_t kk = 0; kk < k; ++kk)
            out += " ";
        out += "    ";
        for (j = 0; j < char_last_line; ++j)
        {
            if (isprint(p[16 * i + j]) && p[16 * i + j] != '%')
                out += (char)p[16 * i + j];
            else
                out += ".";
        }
        out += "\n";
    }
    return std::move(out);
}
////////////////////////////////////////////////////////////////////////////////
inline std::string bin2hex(const std::string& data){
    return std::move(bin2hex(data.c_str(), data.size()));
}
////////////////////////////////////////////////////////////////////////////////
inline std::string wtos(const std::wstring &wstr,const char *locale = 0){
    if (wstr.empty())
        return std::string();

    if (!locale)
        locale = "";
    setlocale(LC_ALL, locale);

    size_t bytes = wcstombs(NULL, wstr.c_str(), 0) + 1;

    std::string str;
    char *pmbuff = new char[bytes + 1];
    memset(pmbuff, 0, (bytes + 1)*sizeof(char));

    size_t size = wcstombs(pmbuff, wstr.c_str(), bytes);
    if (size != (size_t)(-1))
        str = pmbuff;

    delete []pmbuff;
    return std::move(str);
}
////////////////////////////////////////////////////////////////////////////////
inline std::wstring stow(const std::string &str, const char *locale = 0){
    if (str.empty())
        return std::wstring();

    if (!locale)
        locale = "";
    setlocale(LC_ALL, locale);

    size_t bytes = mbstowcs(NULL, str.c_str(), 0) + 1;

    std::wstring wstr;
    wchar_t *pmbuff = new wchar_t[bytes + 1];
    memset(pmbuff,0,(bytes+1)*sizeof(wchar_t));

    size_t size = mbstowcs(pmbuff, str.c_str(), bytes);
    if (size != (size_t) (-1))
        wstr = pmbuff;

    delete []pmbuff;
    return std::move(wstr);
}
////////////////////////////////////////////////////////////////////////////////
inline std::string wtoutf8(const std::wstring &wstr){
    if (wstr.empty())
        return std::string();
    size_t wlen = wstr.size();

    std::string str;
    unsigned char *obuff = new unsigned char[wlen * 3 + 1];
    memset(obuff, 0, wlen * 3 + 1);

    unsigned char *t = obuff;
    wchar_t *us = const_cast<wchar_t*>(wstr.c_str());
    int UNICODE_CHARS = (sizeof(wchar_t) >= 4 ? 0x110000 : 0x10000);

    for (size_t i = 0; i < wlen; i++){
        wchar_t mychar = us[i];
        if (mychar <= 0x7F){
            *t++ = (unsigned char)mychar; /* 7 sig bits */
        } else if (mychar <= 0x7FF){ /* 11 sig bits */
            *t++ = 0xC0 | (unsigned char)(mychar >> 6);   /* upper 5 bits */
            *t++ = 0x80 | (unsigned char)(mychar & 0x3F); /* lower 6 bits */
        } else if (mychar <= 0xFFFF){ /* 16 sig bits */
            *t++ = 0xE0 | (unsigned char)(mychar >> 12);  /* upper 4 bits */
            *t++ = 0x80 | (unsigned char)((mychar >> 6) & 0x3F);  /* next 6 bits */
            *t++ = 0x80 | (unsigned char)(mychar & 0x3F); /* lowest 6 bits */
        } else if (mychar < UNICODE_CHARS){ /* 21 sig bits */
            *t++ = 0xF0 | (unsigned char)((mychar >> 18) & 0x07); /* upper 3 bits */
            *t++ = 0x80 | (unsigned char)((mychar >> 12) & 0x3F); /* next 6 bits */
            *t++ = 0x80 | (unsigned char)((mychar >> 6)  & 0x3F); /* next 6 bits */
            *t++ = 0x80 | (unsigned char)(mychar & 0x3F);         /* lowest 6 bits */
        }
    }
    str = (char*)obuff;
    delete []obuff;
    return std::move(str);
}
////////////////////////////////////////////////////////////////////////////////
inline std::wstring utf8tow(const std::string &str){
    if (str.empty())
        return std::wstring();
    size_t len = str.size();

    std::wstring wstr;
    wchar_t *obuff = new wchar_t[len + 1] ;
    memset(obuff,0,sizeof(wchar_t)*(len + 1));

    char *t = const_cast<char*>(str.c_str());
    char *s = const_cast<char*>(str.c_str());
    
    int length = 0;
    wchar_t *us = obuff;

    while (static_cast<size_t>(s - t) < len){
        if (*(unsigned char *)s <= 0x7f){ /* one byte */
            *us++ = *s++;        /* expand with 0s */
        } else if (*(unsigned char*)s <= 0xdf){ /* 2 byte */
            *us++ = ((*(unsigned char*)s & 0x1f) << 6) + ((*(unsigned char*)(s + 1)) & 0x3f);
            s += 2;
        } else {/* 3 byte */
            *us++ = ((int)(*(unsigned char*)s & 0x0f) << 12) + ((*(unsigned char*)(s + 1) & 0x3f) << 6) + (*(unsigned char*)(s + 2) & 0x3f);
            s += 3;
        }
        length++;
    }
    wchar_t *p1 = obuff+length-1;
    for (int i = 0; i < length; ++i){
        if (*p1 == 9) *p1 = 0; else break;
        --p1;
    }
    wstr = obuff;
    delete []obuff;
    return std::move(wstr);
}
////////////////////////////////////////////////////////////////////////////////
inline bool is_utf8(const char *buf){
    int i, n, f;
    register unsigned char c;
    bool gotone = false;

    const unsigned char F = 0;
    const unsigned char T = 1;
    const unsigned char I = 2;
    const unsigned char X = 3;

    static const unsigned char text_chars[256] = {
        F, F, F, F, F, F, F, T, T, T, T, F, T, T, F, F,
        F, F, F, F, F, F, F, F, F, F, F, T, F, F, F, F,
        T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
        T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
        T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
        T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
        T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
        T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, F,
        X, X, X, X, X, T, X, X, X, X, X, X, X, X, X, X,
        X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
        I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,
        I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,
        I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,
        I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,
        I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,
        I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I
    };
    for (i = f = 0; (c = buf[i]); i++){
        if ((c & 0x80) == 0){
            if (text_chars[c] != T)
                return false;
            f++;
        } else if ((c & 0x40) == 0){
            return false;
        } else {
            int following;
            if ((c & 0x20) == 0)
                following = 1;
            else if ((c & 0x10) == 0)
                following = 2;
            else if ((c & 0x08) == 0)
                following = 3;
            else if ((c & 0x04) == 0)
                following = 4;
            else if ((c & 0x02) == 0)
                following = 5;
            else{
                return false;
            }
            for (n = 0; n < following; n++){
                if (!(c = buf[++i])){
                    break;
                }
                if ((c & 0x80) == 0 || (c & 0x40)){
                    return false;
                }
            }
            if (n < following)
                break;
            gotone = true;
        }
    }
    return (i == f || gotone);
}
////////////////////////////////////////////////////////////////////////////////
inline bool is_utf8(const std::string &str){
    return is_utf8(str.c_str());
}
////////////////////////////////////////////////////////////////////////////////
inline int utf8_size(const char *utf8_str){
    int i = 0, j = 0;
    while (utf8_str[i]){
        if ((utf8_str[i++] & 0xc0) != 0x80)
            j++;
    }
    return j;
}
////////////////////////////////////////////////////////////////////////////////
inline int utf8_size(const std::string &str){
    return utf8_size(str.c_str());
}
////////////////////////////////////////////////////////////////////////////////
inline std::string ctoutf8(const char *str, const char *locale = 0){
    if (is_utf8(str))
        return str;
    return std::move(wtoutf8(stow(str, locale)));
}
////////////////////////////////////////////////////////////////////////////////
inline std::string ctoutf8(const std::string &str, const char *locale = 0){
    return ctoutf8(str.c_str(), locale);
}
////////////////////////////////////////////////////////////////////////////////
inline std::string ctoansi(const char *utf8str, const char *locale = 0){
    if (!is_utf8(utf8str))
        return utf8str;
    return std::move(wtos(utf8tow(utf8str), locale));
}
////////////////////////////////////////////////////////////////////////////////
inline std::string ctoansi(const std::string &str, const char *locale = 0){
    return ctoansi(str.c_str(), locale);
}
////////////////////////////////////////////////////////////////////////////////
inline int utf8_to_vector(const char *utf8_str, std::vector<std::string> &vec){
    vec.clear();
    std::string str;
    int i = 0, j = 0, k = 0;
    while (utf8_str[i]){
        if ((utf8_str[i] & 0xc0) != 0x80){
            j++;
            if (!str.empty()){
                vec.push_back(str);
                str.clear();
            }
        }
        str += utf8_str[i++];
    }
    if (!str.empty())
        vec.push_back(str);
    return j;
}
////////////////////////////////////////////////////////////////////////////////
inline std::string sbc_to_dbc(const char *str){ //全角转半角
    std::string output;
    const char *sbc = str;
    for(; *sbc; ++sbc){
        if((*sbc & 0xff) == 0xA1 && (*(sbc + 1) & 0xff) == 0xA1){ //全角空格
            output += 0x20;
            ++sbc;
        } else if ((*sbc & 0xff) == 0xA3 && (*(sbc + 1) & 0xff) >= 0xA1 && (*(sbc + 1) & 0xff) <= 0xFE){ //ASCII码中其它可显示字符
            output += (*++sbc - 0x80);
        } else {
            if(*sbc < 0) //如果是中文字符，则拷贝两个字节
                output += (*sbc++);
            output += (*sbc);
        }
    }
    return std::move(output);
}
////////////////////////////////////////////////////////////////////////////////
inline std::string sbc_to_dbc(const std::string &str){ //全角转半角
    return sbc_to_dbc(str.c_str());
}
////////////////////////////////////////////////////////////////////////////////
inline std::string dbc_to_sbc(const char *str){ //半角转全角
    std::string output;
    const char *dbc = str;
    for(; *dbc; ++dbc){
        if((*dbc & 0xff) == 0x20){    //半角空格
            output += (char)0xA1;
            output += (char)0xA1;
        } else if((*dbc & 0xff) >= 0x21 && (*dbc & 0xff) <= 0x7E){
            output += (char)0xA3;
            output += (*dbc + (char)0x80);
        } else {
            if(*dbc < 0)    //如果是中文字符，则拷贝两个字节
                output += (*dbc++);
            output += (*dbc);
        }
    }
    return std::move(output);
}
////////////////////////////////////////////////////////////////////////////////
inline std::string dbc_to_sbc(const std::string &str){ //半角转全角
    return dbc_to_sbc(str.c_str());
}
////////////////////////////////////////////////////////////////////////////////
inline std::string utf8_to_dbc(const char *str){
    std::string output, s(str);
    for (size_t j = 0; j < s.size(); j++){
        if (((s[j] & 0xF0) ^ 0xE0) != 0){
            output += s[j];
        } else {
            int c = (s[j] & 0xF) << 12 | ((s[j + 1] & 0x3F) << 6 | (s[j + 2] & 0x3F));
            if (c == 0x3000){ // blank
                char new_char = 0x20;
                output += new_char;
            } else if (c >= 0xFF01 && c <= 0xFF5E){ // full char
                char new_char = c - 0xFEE0;
                output += new_char;
            } else { // other 3 bytes char
                output += s[j];
                output += s[j + 1];
                output += s[j + 2];
            }
            j = j + 2;
        }
    }
    return std::move(output);
}
////////////////////////////////////////////////////////////////////////////////
inline const std::string& strrstr(std::string &str, const std::string &old_value, const std::string &new_value)
{
    std::string::size_type pos = str.find(old_value);
    while(pos != std::string::npos){
        str.replace(pos, old_value.length(), new_value);
        pos = str.find(old_value, pos + new_value.size());
    }
    return str;
}
////////////////////////////////////////////////////////////////////////////////
#endif // __INC_STRING_H_
